<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ECMA练习题</title>
    <style>
        pre {
            font-size: 17px;
        }
    </style>
</head>

<body>
    <script>
        //1. js中ECMAScript，DOM，BOM的含义？

        //2. js中的数据类型有哪些？

        //3. 如何进行数据类型的判断？

        //4. 请写出下面语句的输出结果和原因
        /*
                  var bar = true, number = 0;
                  console.log(bar + 0);
                  console.log(bar + "xyz");
                  console.log(bar + true);
                  console.log(+true);
                  console.log(!'bluej');
                  console.log(number++);
                  console.log(++number);
                  console.log(number);
                */

        //5.循环输出1-100 里奇数

        // 6.在控制台中打印如下星星
        // ✨
        // ✨✨
        // ✨✨✨
        // ✨✨✨✨
        // ✨✨✨✨✨

        //7. 函数的length属性由什么决定

        //8. 分别用for和递归实现一个函数 传入一个数字n，求1+2+3+...+n的和

        //9. 什么是作用域？下列代码会输出什么
        /*
                var age = 10;
                function person() {
                  age = 100;
                  console.log(age);
                  var age;
                  console.log(age);
                }
                person();
                console.log(age)
                */

        //10.什么是作用域链，下列代码会输出什么
        /*
              var a = "apple";
                function fn() {
                  console.log(a);
                  var a = "angle";
                  console.log(ss());
                  function ss() {
                    return a;
                  }
                }
                fn();
                */

        //11.数组的push pop shift unshift 分别有什么用？他们会改变原来的数组吗？

        //12.定义一个函数,能在数组 arr  [1, 2, 3, 4, 2, 5, 2, 6, 7, 8, 9, 0, 1, 4, 3, 2]的 "2"后面添加元素 "哈哈"。不要直接修改数组 arr，结果返回新的数组

        //13.分别写出用indexOf和splice实现对数组去重的代码

        //14.输出arr中年龄小于17的对象
        /*   var arr = [
                  {
                    name: "111",
                    sex: "boy",
                    age: 18,
                  },
                  {
                    name: "222",
                    sex: "girl",
                    age: 17,
                  },
                  {
                    name: "333",
                    sex: "boy",
                    age: 16,
                  },
                  {
                    name: "444",
                    sex: "girl",
                    age: 15,
                  },
                  {
                    name: "555",
                    sex: "boy",
                    age: 20,
                  },
                ]; */

        //15. 封装一个函数，实现字符串的翻转

        //16. 统计数组arr中每个元素的出现次数
        /*
          var arr = [
            "b",
            "a",
            "c",
            "a",
            "b",
            "b",
            "b",
            "c",
            "c",
            "a",
            "c",
            "a",
            "a",
            "a",
            "b",
            "c",
          ]; */

        //17. 统计字符串str中每个字符出现的次数
        /*
          var str= "哈哈哈哈哈哈哈嘻嘻嘻嘻嘻嘻嘻嘻嘿嘿嘿嘿噢噢噢噢噢噢"
          */

        //18. 什么是闭包？下列代码会输出什么？为什么
        /*
        function addCount() {
            var count = 0;
            return function () {
              count += 1;
              console.log(count);
            };
          }
          var foo1 = addCount();
          var foo2 = addCount();
          foo1();
          foo2();
          foo2();
          foo1();
           */

        //19.斐波那契数列是这样的数列：1、1、2、3、5、8、13、21,他的规律是 下标0和下标1的项都是1，从下标为2的那项开始，每项等于前两项之和现在，编写一个函数，功能是返回该数列中下标为n的那项的值

        //20.控制台每隔1s实时打印当前时间，格式为xxxx年xx月xx日 xx:xx:xx

        //21.数组的forEach map filter some every reduce有什么作用？

        //22.什么是深浅拷贝，如何实现深拷贝？深拷贝函数中为何要递归？
    </script>

    <h3>1.</h3>
    <pre>
      ECMASCript:定义了该语言的基本语法和基本对象。
      DOM:文档对象模型(Document Object Model)，描述了处理网页内容的方法和接口。
      BOM:浏览器对象模型(Broswer Object Model)，描述了与浏览器进行交互的方法和接口。
    </pre>

    <h3>2.</h3>
    <pre>
      字符串(string)、数字(number)、布尔值(boolean)、未定义(undefined)、空值(null)、唯一(Symbol)、数组(Array)、对象(Object)、函数(function)
    </pre>

    <h3>3.</h3>
    <pre>
      typeof 无法判断null、Array、object 返回值都是object
      Array.isArray() 判断数组
      Object.prototype.toString.call() 啥都可以
    </pre>

    <h3>4.</h3>
    <pre>
      console.log(bar + 0);  // 1  1 + 0 = 1
      console.log(bar + "xyz");  // truexyz + 进行字符串拼接
      console.log(bar + true);  // 2 1 + 1 = 2
      console.log(+true); // 1   + 会将true转换为数字1
      console.log(!'bluej'); // ! 会将'bluej'先转换为true 再进行去反 得到false
      console.log(number++);  // 0 先用后增 所以 0
      console.log(++number);  // 2 因为上一步此时 number = 1 先增后用 1 + 1 = 2
      console.log(number);  // 2  因为前两步 此时 number = 2
    </pre>

    <h3>5.</h3>
    <pre>
      for (var i = 1; i <= 100; i = i + 2) {
        console.log(i);
    }
    </pre>

    <h3>6.</h3>
    <pre>
      var str = '';
      for (let i = 0; i < 5; i++) {
          str += '✨';
          console.log(str);
      }
    </pre>

    <h3>7.</h3>
    <pre>
      length属性由形参决定的。
    </pre>

    <h3>8.</h3>
    <pre>
      var n = 100;
      function sum(n) {
          var he = 0;
          for (var i = 1; i <= n; i++) {
              he += i;
          }
          return he;
      }
      console.log(sum(n));

      var n = 100;
      function sum(n) {
          if (n == 1) {
              return 1
          } else {
              return n + sum(n - 1);
          }
      }
      console.log(sum(n));
    </pre>

    <h3>9.</h3>
    <pre>
      作用域就是每一个变量都有自己产生作用的范围；
      var age = 10;
      function person() {
        age = 100;
        console.log(age); // 100
        var age; 
        console.log(age); // 100
      }
      person();
      console.log(age) // 10
    </pre>

    <h3>10.</h3>
    <pre>
      作用域链是当一个块或函数嵌套在另一个块或函数中时，就发生了作用域的嵌套。
      var a = "apple";
      function fn() {
        console.log(a); // undefined
        var a = "angle";
        console.log(ss()); // 'angle'  因为ss() 得到一个 a 从而找到 var a = "angle";
        function ss() {
          return a;
        }
      }
      fn();
    </pre>

    <h3>11.</h3>
    <pre>
      push会在末尾进行添加 pop会在末尾进行删除 shift会在头部进行删除 unshift会在头部进行添加 
      不会改变数组
    </pre>

    <h3>12.</h3>
    <pre>
      var arr = [1, 2, 3, 4, 2, 5, 2, 6, 7, 8, 9, 0, 1, 4, 3, 2];
      var newarr = [];
      for (var i = 0; i < arr.length; i++) {
          if (arr[i] == 2) {
              newarr.push(arr[i],'哈哈')
          } else {
              newarr.push(arr[i]);
          }
      }
      console.log(newarr);
    </pre>

    <h3>13.</h3>
    <pre>
      var arr = [1, 2, 3, 9, 5, 2, 3, 7, 8, 8, 9, 9];
      var newarr = [];
      for (var i = 0; i < arr.length; i++) {
          if (newarr.indexOf(arr[i]) == -1) {
              newarr.push(arr[i]);
          }
      }
      console.log(newarr);

      var arr = [1, 2, 3, 9, 5, 2, 3, 7, 8, 8, 9, 9];
      for (var i = 0; i < arr.length; i++) {
          for (var j = i + 1; j < arr.length; j++) {
              if (arr[i] == arr[j]) {
                  arr.splice(j, 1);
                  j--
              }
          }
      }
      console.log(arr);
    </pre>

    <h3>14.</h3>
    <pre>
      var arr = [
      {
        name: "111",
        sex: "boy",
        age: 18,
      },
      {
        name: "222",
        sex: "girl",
        age: 17,
      },
      {
        name: "333",
        sex: "boy",
        age: 16,
      },
      {
        name: "444",
        sex: "girl",
        age: 15,
      },
      {
        name: "555",
        sex: "boy",
        age: 20,
      },
    ];
      var newarr = arr.filter(function(ele) {
        return ele.age < 17;
    })
    console.log(newarr);
    </pre>

    <h3>15.</h3>
    <pre>
      var str = '牛奶';
      function fz(str) {
          str = str.split('').reverse().join('');
          return str;
      }
      console.log(fz(str));
    </pre>

    <h3>16.</h3>
    <pre>
      var arr = [
      "b",
      "a",
      "c",
      "a",
      "b",
      "b",
      "b",
      "c",
      "c",
      "a",
      "c",
      "a",
      "a",
      "a",
      "b",
      "c",
  ];
  var obj = {};
  for (var i = 0; i < arr.length; i++) {
      if (obj[arr[i]]) {
          obj[arr[i]] += 1
      } else {
          obj[arr[i]] = 1;
      }
  }
  console.log(obj);
    </pre>

    <h3>17.</h3>
    <pre>
      var str = "哈哈哈哈哈哈哈嘻嘻嘻嘻嘻嘻嘻嘻嘿嘿嘿嘿噢噢噢噢噢噢"
      var newstr = str.split('');
      var obj = {};
      for (var i = 0; i < newstr.length; i++) {
          if (obj[newstr[i]]) {
              obj[newstr[i]] += 1
          } else {
              obj[newstr[i]] = 1;
          }
      }
      console.log(obj);
    </pre>

    <h3>18.</h3>
    <pre>
      闭包是函数本身和该函数声明时所处的环境状态的组合。
      function addCount() {
        var count = 0;
        return function () {
          count += 1;
          console.log(count);
        };
      }
      var foo1 = addCount();
      var foo2 = addCount();
      foo1(); // 1   count += 1;
      foo2(); // 1   因为闭包的性质，模拟私有变量。
      foo2(); // 2   因为闭包的性质, 记忆性。2 =  1 + 1。
      foo1(); // 2   同理
    </pre>

    <h3>19.</h3>
    <pre>
      function bo(n) {
        if (n === 0 || n === 1) {
            return 1;
        } else {
            return bo(n - 1) + bo(n - 2)
        }
    }
    console.log(bo(2));
    </pre>

    <h3>20.</h3>
    <pre>
      setInterval(sj, 1000);

      function sj() {
          var newdata = new Date();
          var n = newdata.getFullYear();
          var y = newdata.getMonth() + 1;
          var r = newdata.getDate();
          var x = newdata.getHours();
          var f = newdata.getMinutes();
          var m = newdata.getSeconds();
          y = y < 10 ? '0' + y : y;
          r = r < 10 ? '0' + r : r;
          x = x < 10 ? '0' + x : x;
          f = f < 10 ? '0' + f : f;
          m = m < 10 ? '0' + m : m;
          console.log(`${n}年${y}月${r}日${x}:${f}:${m}`);
      }
    </pre>

    <h3>21.</h3>
    <pre>
      forEach 遍历数组
      map 对数组内每个元素进行操作
      filter 过滤器
      some 一个为ture 就返回为true
      every 所以为ture 返回为true
      reduce 累加器
    </pre>

    <h3>22.</h3>
    <pre>
      引用数据类型在复制时，改变其中一个数据的值，另一个数据的值也会跟着改变，这种拷贝方式我们称为浅拷贝。
      引用类型复制到新的变量后，二者是独立的，不会因为一个的改变而影响到另一个，这种拷贝方式就称为深拷贝。
      防止引用类型里又包含一个引用类型。

      function ss(data) {
        if (Array.isArray(data)) {
            var result = [];
            for (var i = 0; i < data.length; i++) {
                result.push(ss(data[i]));
            }
        } else if (typeof data === 'object') {
            var result = {};
            for (var key in data) {
                result[key] = ss(data[key]);
            }
        } else {
            var result = data;
        }
        return result;
      }

      var obj = {
        name: 'sss',
        persons: [{
            nas: 'sssdsad'
        }, {
            dadasd: 'rewrwrwe'
        }]
      }
      var obj1 = ss(obj);
      obj1.persons[0].nas = 'wwwww';
      console.log(obj, obj1);
    </pre>
</body>

</html>